/***************************** Client TCP *****************************
 * Nom ......... : GUI_Client.c                                       *
 * Role ........ : Client de chat. Le code permet l'                  *
 *                 interactions avec le serveur                       *
 * Auteur ...... : Niroj Edward & Jonas Marquis                       *
 * Version ..... : V1 du 01/01/2014                                   *
 * Licence ..... : GPL                                                *
 *                                                                    *
 * Compilation :                                                      *
 * gcc -Wall -o client client.c `pkg-config --cflags --libs gtk+-2.0` *
 * Pour exécuter, tapez : ./Client                                    *
 *********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <fcntl.h>
#include <memory.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>


#define MAX_MSG 250


/* Variables globales pour interface graphique */
GtkWidget *window;
GtkWidget *table, *table_connect, *table_msgs, *table_file, *scroll_tview, *scroll_tview_users;
GtkWidget *frame_connect, *frame_msgs, *frame_users, *frame_file;
GtkWidget *label_adr, *entry_adr, *label_port, *entry_port, *label_login, *entry_login, *label_msg, *entry_msg, *label_file_user, *entry_file_user, *entry_filename;
GtkWidget *button_connect, *button_send, *button_file, *button_browse;
GtkWidget *tview, *tview_users;
GtkWidget *file_dialog;

GtkEntryBuffer *entry_adr_buf, *entry_port_buf, *entry_login_buf, *entry_msg_buf, *entry_file_user_buf, *entry_filename_buf;
GtkTextBuffer *tview_buffer, *tview_users_buffer;
GtkTextIter iter, iter2;
gchar *file_name;

int sockfd;
int iType;
char Login[50];
/***********************************************/

/******************* Fonction appelée si clique bouton Connexion *******************/
void fonction_Connect(void) {
    const gchar *adr_serveur, *port_serveur, *login;

    // Récupération de l'adresse et port du serveur et du login de l'utilisateur pour connexion
    adr_serveur = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_adr_buf));
    port_serveur = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_port_buf));
    login = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_login_buf));


    /***** TO DO *****/
    int new_fd, rv;
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr their_adr;
    socklen_t addrlen;
    // buffer données client
    char buf[256] = "3"; // id indiquant que c'est un login pour le serveur
    int numbytes;
    //char message[20] = "3"+login;//id qui permet de savoir si le message envoyé est un client

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    rv = getaddrinfo(adr_serveur, port_serveur, &hints, &servinfo);
    if (rv != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    //récupération du login avec l'identifient
    strcpy(Login, gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_login_buf)));
    strcat(buf, Login);

    // Création socket et attachement
    for (p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
            perror(" client: socket");
            continue;
        }
        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("client: connect");
            continue;
        }
        break;
    }

    if (p == NULL) {
        fprintf(stderr, "server: failed to bind\n");
        return 2;
    }
    freeaddrinfo(servinfo); // Libère structure
    listen(sockfd, 5);

    iType = 3;
    sprintf(buf, "%d%s", iType, Login);


    //envoie du login au serveur
    if ((numbytes = send(sockfd, buf, strlen(buf), 0)) == -1) {
        printf("Erreur envoie\n");
    }

    //THREAD DE RECEPTION

    void * thread2() {

        char cType[1], cDimData[4];
        char cLogin[2], cNameLogin[50];
        int iDimData;
        int iLogin;
        int iType;

        int numbytes;
        char buf[256] = "";
        char Type[256];
        char cTailleMsg[256];
        int iTailleMsg;
        char LoginExterne[256];
        int egal;
        while (1) {

            if ((numbytes = recv(sockfd, buf, sizeof buf, 0)) == -1) {
                Affiche_msg("utilisateur", "erreur");
            } else {
                snprintf(Type, 2, "%s", buf);
                printf("Type de message : %s \n", Type);
                // Un message
                egal = strcmp(Type, "1");
                if (egal == 0) {
                    sprintf(buf, "%s", buf + 1);
                    snprintf(cTailleMsg, 2, "%s", buf); //taille Login
                    iTailleMsg = atoi(cTailleMsg);
                    printf("Taille du message : %d \n", iTailleMsg);
                    sprintf(buf, "%s", buf + 1);
                    snprintf(LoginExterne, iTailleMsg + 1, "%s", buf); //Récupération du login externe
                    sprintf(buf, "%s", buf + iTailleMsg);
                    Affiche_msg(LoginExterne, buf);
                }

                // Une connexion
                egal = strcmp(Type, "3");
                if (egal == 0) {

                    snprintf(cLogin, 4, "%s", buf + 1);
                    printf("ID : %d \n", iLogin);
                    sprintf(cNameLogin, "%s", buf + 3);
                    printf("Login : %s \n", cNameLogin);

                    Affiche_users(iLogin, cNameLogin);
                }

                // Un fichier
                egal = strcmp(Type, "2");
                if (egal == 0) {

                }
            }
        }
    }

    pthread_t ta;

    pthread_create(&ta, NULL, thread2, NULL);

}

/******************* Fonction permettant affichage nouvel utilisateur connecté *******************/
void Affiche_users(char *num, gchar *login) {
    const gchar *user_display;

    // Reconstitue info à afficher
    user_display = g_strconcat(num, " - ", login, "\n", NULL);
    // Affichage du utilisateur
    gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(tview_users_buffer), user_display, strlen(user_display));
    // Force déroulement jusqu'à la dernière ligne
    gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(tview_users_buffer), &iter2);
    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(tview_users), &iter2, 0.0, FALSE, 0, 0);
}

/******************* Fonction permettant affichage message sur espace Communication *******************/
void Affiche_msg(gchar *user, gchar *msg) {
    const gchar *msg_display;

    // Reconstitue message à afficher
    msg_display = g_strconcat(user, " : ", msg, "\n", NULL);
    // Affichage du message
    gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(tview_buffer), msg_display, strlen(msg_display));
    // Force déroulement jusqu'au message le plus récent
    gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(tview_buffer), &iter);
    gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(tview), &iter, 0.0, FALSE, 0, 0);
}

/******************* Fonction appelée si clique bouton Envoyer (message) *******************/
void fonction_Envoie(void) {
    //const gchar *msg;
    char msg[256];
    const gchar *type = "1";
    gchar *user = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_login_buf));



    int numbytes;
    //char Messagerecu[256];
    // Récupération du message à envoyer
    // msg = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_msg_buf));
    strcpy(msg, gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_msg_buf)));

    // Supprime le message dans l'entrée Message
    gtk_entry_buffer_delete_text(GTK_ENTRY_BUFFER(entry_msg_buf), 0, strlen(msg));


    /***** TO DO *****/

    //ajout du type dans le message
    //msg = g_strdup_printf("%s %s", type, msg);

    iType = 1;
    char cBuffer[256];

    sprintf(cBuffer, "%d%d%s%s", iType, strlen(Login), Login, msg);

    if ((numbytes = send(sockfd, cBuffer, strlen(cBuffer), 0)) == -1) {
        printf("Erreur envoie\n");
    }

    Affiche_msg("Moi", msg);


    //pthread_join(ta,NULL);
}

/******************* Fonction appelée si clique bouton Envoyer fichier *******************/
void fonction_Envoie_Fichier(void) {
    const gchar *dest;

    // Récupération numéro destinataire fichier
    dest = gtk_entry_buffer_get_text(GTK_ENTRY_BUFFER(entry_file_user_buf));

    /***** TO DO *****/

    int numbytes,file;
    char cBuffer[256], cDest[2];
    iType = 4;
    if (dest < 10) {
        sprintf(cDest, "0%d", dest);
    } else {
        sprintf(cDest, "%d", dest);
    }
    //à revoir
    bzero(buf,256);
    file=open(file_name, O_RDONLY);
    sprintf(cBuffer, "%d%s%s", iType, cDest, cBuffer);
    while((cpt=read(file, buf, TAILLE_BUF))>0){
       
    }
    if ((numbytes = send(sockfd, cBuffer, strlen(cBuffer), 0)) == -1) {
        printf("Erreur envoie\n");
    }
}

/******************* Fonction récupérant fichier sélectionné si appuie bouton OK  *******************/
void file_ok_sel(GtkWidget *w, GtkFileSelection *fs) {
    // Récupère le nom du fichier séléctionné par l'utilisateur
    file_name = (char *) gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs));
    gtk_widget_destroy(file_dialog);
    gtk_entry_buffer_set_text(entry_filename_buf, file_name, strlen(file_name));
}

/******************* Affichage boite dialogue selection fichier si appuie bouton Parcourir *******************/
void fonction_Affich_FSelect(void) {
    // Création de la boite de dialogue pour selection fichier
    file_dialog = gtk_file_selection_new("Choix du fichier");
    g_signal_connect(file_dialog, "destroy", G_CALLBACK(gtk_widget_destroy), NULL);
    /* Connecte bouton Ok à la fonction file_ok_sel */
    g_signal_connect(GTK_FILE_SELECTION(file_dialog)->ok_button, "clicked", G_CALLBACK(file_ok_sel), (gpointer) file_dialog);
    /* Connecte bouton Cancel à la fonction de destruction du widget */
    g_signal_connect_swapped(GTK_FILE_SELECTION(file_dialog)->cancel_button, "clicked", G_CALLBACK(gtk_widget_destroy), file_dialog);
    gtk_widget_show(file_dialog);
}

/******************* Fonction créant interface client *******************/
void Aff_interface(int argc, char *argv[]) {
    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_resizable(GTK_WINDOW(window), TRUE);

    gtk_window_set_title(GTK_WINDOW(window), "Client pour chat");
    gtk_container_set_border_width(GTK_CONTAINER(window), 15);

    table = gtk_table_new(3, 2, FALSE);
    gtk_table_set_col_spacings(GTK_TABLE(table), 10);
    gtk_table_set_row_spacings(GTK_TABLE(table), 5);


    frame_connect = gtk_frame_new("Connexion au serveur");
    gtk_frame_set_shadow_type(GTK_FRAME(frame_connect), GTK_SHADOW_ETCHED_IN);
    gtk_table_attach(GTK_TABLE(table), frame_connect, 0, 1, 0, 1, 0, 0, 0, 0);
    table_connect = gtk_table_new(2, 4, FALSE);
    gtk_table_set_col_spacings(GTK_TABLE(table_connect), 10);
    gtk_table_set_row_spacings(GTK_TABLE(table_connect), 5);
    gtk_container_set_border_width(GTK_CONTAINER(table_connect), 10);
    gtk_container_add(GTK_CONTAINER(frame_connect), table_connect);

    label_adr = gtk_label_new("Adresse :");
    entry_adr = gtk_entry_new();
    entry_adr_buf = gtk_entry_buffer_new(NULL, -1);
    gtk_entry_buffer_set_max_length(GTK_ENTRY_BUFFER(entry_adr_buf), 15);
    gtk_entry_set_buffer(GTK_ENTRY(entry_adr), GTK_ENTRY_BUFFER(entry_adr_buf));

    label_port = gtk_label_new("Port :");
    entry_port = gtk_entry_new();
    entry_port_buf = gtk_entry_buffer_new(NULL, -1);
    gtk_entry_buffer_set_max_length(GTK_ENTRY_BUFFER(entry_port_buf), 5);
    gtk_entry_set_buffer(GTK_ENTRY(entry_port), GTK_ENTRY_BUFFER(entry_port_buf));

    gtk_table_attach_defaults(GTK_TABLE(table_connect), label_adr, 0, 1, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), entry_adr, 1, 2, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), label_port, 2, 3, 0, 1);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), entry_port, 3, 4, 0, 1);

    label_login = gtk_label_new("Login :");
    entry_login = gtk_entry_new();
    entry_login_buf = gtk_entry_buffer_new(NULL, -1);
    gtk_entry_buffer_set_max_length(GTK_ENTRY_BUFFER(entry_login_buf), 50);
    gtk_entry_set_buffer(GTK_ENTRY(entry_login), GTK_ENTRY_BUFFER(entry_login_buf));

    button_connect = gtk_button_new_with_label("Connexion");
    g_signal_connect(G_OBJECT(button_connect), "clicked", G_CALLBACK(fonction_Connect), NULL);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), label_login, 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), entry_login, 1, 2, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table_connect), button_connect, 3, 4, 1, 2);


    frame_msgs = gtk_frame_new("Communication");
    gtk_frame_set_shadow_type(GTK_FRAME(frame_msgs), GTK_SHADOW_ETCHED_IN);
    gtk_table_attach_defaults(GTK_TABLE(table), frame_msgs, 0, 1, 1, 2);
    table_msgs = gtk_table_new(2, 3, FALSE);
    gtk_table_set_col_spacings(GTK_TABLE(table_msgs), 10);
    gtk_table_set_row_spacings(GTK_TABLE(table_msgs), 5);
    gtk_container_set_border_width(GTK_CONTAINER(table_msgs), 10);
    gtk_container_add(GTK_CONTAINER(frame_msgs), table_msgs);

    scroll_tview = gtk_scrolled_window_new(NULL, NULL);
    gtk_widget_set_size_request(GTK_WIDGET(scroll_tview), 500, 300);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_tview), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
    tview = gtk_text_view_new();
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tview), GTK_WRAP_WORD);
    tview_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tview));
    gtk_text_buffer_create_tag(tview_buffer, "gap", "pixels_above_lines", 30, NULL);
    gtk_text_buffer_create_tag(tview_buffer, "lmarg", "left_margin", 5, NULL);
    gtk_text_buffer_get_iter_at_offset(tview_buffer, &iter, 0);
    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(tview), 10);
    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(tview), 10);
    gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(tview), 10);
    gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(tview), 10);
    gtk_text_view_set_editable(GTK_TEXT_VIEW(tview), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tview), FALSE);
    gtk_container_add(GTK_CONTAINER(scroll_tview), tview);
    gtk_table_attach_defaults(GTK_TABLE(table_msgs), scroll_tview, 0, 3, 0, 1);

    label_msg = gtk_label_new("Message :");
    entry_msg = gtk_entry_new();
    gtk_widget_set_size_request(GTK_WIDGET(entry_msg), 400, 30);
    entry_msg_buf = gtk_entry_buffer_new(NULL, -1);
    gtk_entry_buffer_set_max_length(GTK_ENTRY_BUFFER(entry_msg_buf), MAX_MSG);
    gtk_entry_set_buffer(GTK_ENTRY(entry_msg), GTK_ENTRY_BUFFER(entry_msg_buf));

    button_send = gtk_button_new_with_label("Envoyer");
    g_signal_connect(G_OBJECT(button_send), "clicked", G_CALLBACK(fonction_Envoie), NULL);
    gtk_table_attach_defaults(GTK_TABLE(table_msgs), label_msg, 0, 1, 1, 2);
    gtk_table_attach_defaults(GTK_TABLE(table_msgs), entry_msg, 1, 2, 1, 2);
    gtk_table_attach(GTK_TABLE(table_msgs), button_send, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);


    frame_users = gtk_frame_new("Utilisateurs");
    gtk_frame_set_shadow_type(GTK_FRAME(frame_users), GTK_SHADOW_ETCHED_IN);
    gtk_table_attach_defaults(GTK_TABLE(table), frame_users, 1, 2, 1, 2);

    scroll_tview_users = gtk_scrolled_window_new(NULL, NULL);
    gtk_widget_set_size_request(GTK_WIDGET(scroll_tview_users), 190, 300);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_tview_users), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
    tview_users = gtk_text_view_new();
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tview), GTK_WRAP_WORD);
    tview_users_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tview_users));
    gtk_text_buffer_create_tag(tview_users_buffer, "gap", "pixels_above_lines", 30, NULL);
    gtk_text_buffer_create_tag(tview_users_buffer, "lmarg", "left_margin", 5, NULL);
    gtk_text_buffer_get_iter_at_offset(tview_users_buffer, &iter, 0);
    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(tview_users), 10);
    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(tview_users), 10);
    gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(tview_users), 10);
    gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(tview_users), 10);
    gtk_text_view_set_editable(GTK_TEXT_VIEW(tview_users), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tview_users), FALSE);
    gtk_container_set_border_width(GTK_CONTAINER(tview_users), 5);
    gtk_container_add(GTK_CONTAINER(scroll_tview_users), tview_users);
    gtk_container_add(GTK_CONTAINER(frame_users), scroll_tview_users);


    frame_file = gtk_frame_new("Envoie de fichier");
    gtk_frame_set_shadow_type(GTK_FRAME(frame_file), GTK_SHADOW_ETCHED_IN);
    gtk_table_attach_defaults(GTK_TABLE(table), frame_file, 0, 1, 2, 3);
    table_file = gtk_table_new(1, 5, FALSE);
    gtk_table_set_col_spacings(GTK_TABLE(table_file), 10);
    gtk_table_set_row_spacings(GTK_TABLE(table_file), 5);
    gtk_container_set_border_width(GTK_CONTAINER(table_file), 10);
    gtk_container_add(GTK_CONTAINER(frame_file), table_file);

    entry_filename = gtk_entry_new();
    entry_filename_buf = gtk_entry_buffer_new(NULL, -1);
    gtk_entry_set_buffer(GTK_ENTRY(entry_filename), GTK_ENTRY_BUFFER(entry_filename_buf));

    button_browse = gtk_button_new_with_label("Parcourir");
    g_signal_connect(G_OBJECT(button_browse), "clicked", G_CALLBACK(fonction_Affich_FSelect), NULL);

    label_file_user = gtk_label_new("Destinataire :");
    entry_file_user = gtk_entry_new();
    entry_file_user_buf = gtk_entry_buffer_new("0", 1);
    gtk_entry_buffer_set_max_length(GTK_ENTRY_BUFFER(entry_file_user_buf), 2);
    gtk_entry_set_buffer(GTK_ENTRY(entry_file_user), GTK_ENTRY_BUFFER(entry_file_user_buf));

    button_file = gtk_button_new_with_label("Envoyer fichier");
    g_signal_connect(G_OBJECT(button_file), "clicked", G_CALLBACK(fonction_Envoie_Fichier), NULL);
    gtk_table_attach(GTK_TABLE(table_file), entry_filename, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
    gtk_table_attach(GTK_TABLE(table_file), button_browse, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
    gtk_table_attach(GTK_TABLE(table_file), label_file_user, 2, 3, 0, 1, 0, 0, 0, 0);
    gtk_table_attach(GTK_TABLE(table_file), entry_file_user, 3, 4, 0, 1, 0, 0, 0, 0);
    gtk_table_attach(GTK_TABLE(table_file), button_file, 4, 5, 0, 1, 0, 0, 0, 0);

    gtk_container_add(GTK_CONTAINER(window), table);


    gtk_widget_show_all(window);

    g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_main();
}

int main(int argc, char *argv[]) {

    Aff_interface(argc, argv);



    /***** TO DO *****/


    exit(0);
}
